package com.sxf.biz.ocr.service;

import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.auth.ICredential;
import com.huaweicloud.sdk.core.exception.ConnectionException;
import com.huaweicloud.sdk.core.exception.RequestTimeoutException;
import com.huaweicloud.sdk.core.exception.ServiceResponseException;
import com.huaweicloud.sdk.ocr.v1.OcrClient;
import com.huaweicloud.sdk.ocr.v1.model.BankcardRequestBody;
import com.huaweicloud.sdk.ocr.v1.model.RecognizeBankcardRequest;
import com.huaweicloud.sdk.ocr.v1.model.RecognizeBankcardResponse;
import com.huaweicloud.sdk.ocr.v1.region.OcrRegion;
import com.sxf.biz.subjects.vo.BankOcrRes;
import com.sxf.common.exceptions.BusinessException;
import com.sxf.consts.Consts;
import com.sxf.consts.YtConsts;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.im4java.core.ConvertCmd;
import org.im4java.core.IMOperation;
import org.im4java.process.Pipe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;

/**
 * @description: TODO
 * @Author Leo
 * @date 2024/3/2721:35
 */
@Service
public class OcrService {

    private static final Logger logger = LoggerFactory.getLogger(OcrService.class);
    private static final String OCR_URL = "https://ocr.cn-east-3.myhuaweicloud.com/v2/90c7e1567123428faa784d745c89da09/ocr/bankcard";
    private static final String HUA_WEI_TOKEN_RUL = "https://iam.cn-east-3.myhuaweicloud.com/v3/auth/tokens";

    private static final String accessKey = "I2HIMCWB7BSU5PHJHJDL";
    private static final String secretKey = "o3zAArJE7RwqayPHHEDqxCTmIJAb9A5FR0nMAVfb";

    @Value("${sxf.file.store.path.bank:/data/file/bank/}")
    private String fileStorePath;
    @Value("${sxf.file.ocr.fileAvailabel4M:4194304}")
    private Long fileAvailabel4M;
    @Value("${sxf.file.store.url:}")
    private String fileStoreUrl;

    @Value("${sxf.file.accuracy:0.9}")
    private Double accuracy;



    public BankOcrRes bankCardOcr(MultipartFile file){
        //todo
        // 1.校验
        if (Objects.isNull(file) || file.getSize() == 0) {
            throw new BusinessException("未收到所传文件或者所传文件大小为0");
        }

        // 2.获取后缀
        String suffix = "";
        logger.info("原文件名为{}", file.getOriginalFilename());
        if (file.getOriginalFilename().indexOf(".") > -1) {
            suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
        } else {
            suffix = Optional.ofNullable(file.getOriginalFilename()).orElse("");
        }

        // 3.校验后缀
        if (!YtConsts.ALLOW_FILE.contains(suffix.toLowerCase())) {
            throw new BusinessException(file.getOriginalFilename() + "该文件类型不允许上传！");
        }

        String baseStr = transferFile(file);
        RecognizeBankcardResponse bankcardResponse = ocr(baseStr);

        String fileDiskPath = saveFileToDisk(file,suffix);

        BankOcrRes bankOcrRes = new BankOcrRes();
        if(bankcardResponse.getResult() != null){
//            throw new BusinessException("银行卡识别异常");
            bankOcrRes.setAccountNo(bankcardResponse.getResult().getCardNumber());
            bankOcrRes.setBankName(bankcardResponse.getResult().getBankName());
            bankOcrRes.setType(bankcardResponse.getResult().getType());
        }
        bankOcrRes.setCardUrl(fileDiskPath);
        return bankOcrRes;
    }

    private String transferFile(MultipartFile file) {
        String baseStr = null;
        try {
            baseStr = Base64Encoder.encode(file.getBytes());
            logger.error(baseStr);
//            FileCompressUtil.encodingCompress(baseStr, fileAvailabel4M);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return baseStr;
    }


    public RecognizeBankcardResponse ocr(String base64File){
//        String ak = System.getenv("CLOUD_SDK_AK");
//        String sk = System.getenv("CLOUD_SDK_SK");

        ICredential auth = new BasicCredentials()
                .withAk(accessKey)
                .withSk(secretKey);

        OcrClient client = OcrClient.newBuilder()
                .withCredential(auth)
                .withRegion(OcrRegion.valueOf("cn-east-3"))
                .build();
        RecognizeBankcardRequest request = new RecognizeBankcardRequest();
        BankcardRequestBody body = new BankcardRequestBody();
        body.withImage(base64File);
        request.withBody(body);
        RecognizeBankcardResponse response = new RecognizeBankcardResponse();
        try {
            response = client.recognizeBankcard(request);
            logger.error(response.toString());
        } catch (ConnectionException e) {
            e.printStackTrace();
            logger.error("Ocr 识别连接异常",e.getMessage());
//            throw new BusinessException("银行卡识别异常");
        } catch (RequestTimeoutException e) {
            e.printStackTrace();
            logger.error("Ocr 识别请求超时",e.getMessage());
//            throw new BusinessException("银行卡识别异常");
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("华为云数据返回异常",e.getMessage());
//            throw new BusinessException("银行卡识别异常");
        }
        return response;
    }

    private String saveFileToDisk(MultipartFile file,String suffix){

//        File tmpFile = generateTmpFile("jpg");
//        try (InputStream in = file.getInputStream();) {
//            tmpFile = typeToJpg(tmpFile, in);
//            commpressPicCycle(tmpFile);
//        } catch (Exception e) {
//            logger.error("银行卡文件上传失败！", e.getMessage());
//            throw new BusinessException("银行卡上传失败！");
//        } finally {
//            FileUtil.del(tmpFile);
//        }
        String filepath = saveFile(file,suffix);
        return filepath;
    }

    private String saveFile(MultipartFile file,String suffix) {
        String dataStr = DateUtil.format(new Date(), Consts.DATE_PATTERN);
        String fileName =  getUuid(suffix);
        String filepath = getFilePath(dataStr) + fileName;
        try{
            File dir = new File(getFilePath(dataStr));
            if(!dir.exists()){
                dir.mkdirs();
            }
            File temp = new File(filepath);
            if (!temp.exists()) {
                temp.createNewFile();
            }
            FileUtils.copyInputStreamToFile(file.getInputStream(), temp);
        }catch (IOException e){
            logger.error("保存文件至本地失败",filepath,e);
            throw new BusinessException("银行卡保存失败");
        }

        if(isWindows()){
            return fileStoreUrl  + dataStr + "\\"+ fileName;
        }else {
            return fileStoreUrl + dataStr + "/" + fileName;
        }
    }

    private String getUuid(String suffix){
        return UUID.randomUUID().toString().replace("-", "").toUpperCase() + "." + suffix;
    }


    public File generateTmpFile(String suffix) {
        StringBuffer tmpFilePath = new StringBuffer(FileUtil.getTmpDirPath());
        tmpFilePath.append(UUID.randomUUID().toString().replace("-", "").toUpperCase());
        tmpFilePath.append(".").append(suffix);
        return new File(tmpFilePath.toString());
    }

    /**
     * 根据指定大小和指定精度压缩图片
     *
     * @param desFile     目标图片
     * @param desFilesize 指定图片大小，单位kb
     * @param accuracy    精度，递归压缩的比率，建议小于0.9
     * @return
     * @throws IOException
     */
    private void commpressPicCycle(File desFile) throws Exception {
        long srcFileSizeJPG = desFile.length();
        BufferedImage bim = ImageIO.read(desFile);
        int width = bim.getWidth();
        int heigth = bim.getHeight();
        // 2、判断大小，如果小于2Mb，不压缩；如果大于等于2Mb，压缩
        while (srcFileSizeJPG > 2048 * 1024) {
            width = new BigDecimal(width).multiply(new BigDecimal(accuracy)).intValue();
            heigth = new BigDecimal(heigth).multiply(new BigDecimal(accuracy)).intValue();

            ConvertCmd cmd = new ConvertCmd(true);
            IMOperation op = new IMOperation();
            op.addImage(desFile.getPath());

            op.thumbnail(width, heigth);
            op.quality(80.0);
            op.units("pixelsperinch");
            op.density(90);
            op.strip();
            op.addImage(desFile.getPath());
            cmd.run(op);
            srcFileSizeJPG = desFile.length();
        }
    }

    private File typeToJpg(File target, InputStream is) {
        try (ByteArrayOutputStream os = new ByteArrayOutputStream();) {
            IMOperation op = new IMOperation();
            Pipe pipeIn = new Pipe(is, null);
            Pipe pipeOut = new Pipe(null, os);
            op.addImage("-");
            op.addImage("-");
            ConvertCmd cmd = new ConvertCmd(true);
            cmd.setInputProvider(pipeIn);
            cmd.setOutputConsumer(pipeOut);
            cmd.run(op);
            return FileUtil.writeFromStream(new ByteArrayInputStream(os.toByteArray()), target);
        } catch (Exception e) {
            logger.error("执行图片处理失败-{}", e.getMessage());
            throw new BusinessException("执行图片处理失败");
        }
    }

    private static boolean isImg(String suffix) {
        if (StringUtils.isEmpty(suffix)) {
            return false;
        }
        if (Arrays.stream(YtConsts.SUFFIX_ARRAY).anyMatch(suf -> suf.equals(suffix.toLowerCase()))) {
            return true;
        }
        return false;
    }

    private String getFilePath(String dataStr){
        if(isWindows()){
            return "D:\\data\\file\\" + dataStr + "\\";
        } else {
            return fileStorePath + dataStr + "/";
        }
    }

    private boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().contains("windows");
    }


}
